/*
 * Copyright (C) 2017-2025
 * ZKMall All rights reserved, Designed By 深圳中科鑫智科技有限公司
 * Copyright authorization contact 18814114118
 */
package com.shop.zkmall.commons.poi.export;

import com.shop.zkmall.commons.poi.ImportExeclUtil;
import com.shop.zkmall.commons.utils.StringUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.VerticalAlignment;

import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

/**
 * @author zkmall zkmallvip@163.com
 */
public class ExcelExportUtils {

    private static float title_row_height = 35;
    private static float data_row_height = 25;

    public static void exportExcel(HttpServletRequest request, HttpServletResponse response, String fileName, List<?> excelDatas, Class<?> clz) {
        try {
            HSSFWorkbook resultWb = new HSSFWorkbook();
            HSSFSheet sheet = resultWb.createSheet();
            resultWb.setSheetName(0, fileName);
            //根据类类型信息获取导出的excel对应的标题和列宽 key-列号，value-标题和列宽
            HashMap<Integer, TitleAndCloumn> orderTitleAndCloumnMap = getTitleAndCloumnMap(clz);

            //设置列宽
            orderTitleAndCloumnMap.forEach((k, v) -> sheet.setColumnWidth(k, v.getCloumn() * 256));

            HSSFRow row0 = sheet.createRow(0);
            //设置标题行高
            row0.setHeightInPoints(title_row_height);

            //创建标题单元格格式
            HSSFCellStyle titleCellStyle = getCellStyle(resultWb, 11, true, HSSFColor.BLACK.index, HSSFColor.WHITE.index);
            //填充标题行内容
            orderTitleAndCloumnMap.forEach((k, v) -> {
                HSSFCell row0Cell = row0.createCell(k);
                row0Cell.setCellValue(v.getTitle());
                row0Cell.setCellStyle(titleCellStyle);
            });

            //创建正文单元格格式
            HSSFCellStyle dataStyle = getCellStyle(resultWb, 11, false, HSSFColor.BLACK.index, HSSFColor.WHITE.index);

            //将正文转换为excel数据
            int rowNum = 1;
            for (Object data : excelDatas) {

                HSSFRow row = sheet.createRow(rowNum++);
                row.setHeightInPoints(data_row_height);
                //获取对象值 key-列号 value-String值
                HashMap<Integer, String> orderValueMap = getValueMap(data);
                orderValueMap.forEach((k, v) -> {
                            HSSFCell cell = row.createCell(k);
                            cell.setCellValue(v);
                            cell.setCellStyle(dataStyle);
                        }
                );
            }

            String downFileName = fileName + "_" + ImportExeclUtil.DateUtil.dateToStr(new Date(), ImportExeclUtil.DateUtil.YYYYMMDDHHMMSS) + ".xls";
            response.setContentType("application/vnd.ms-excel; charset=UTF-8");
            response.setHeader("Content-Disposition", "attachment; "
                    + encodeFileName(request, downFileName));

            OutputStream outputStream = response.getOutputStream();
            resultWb.write(outputStream);
            outputStream.flush();
            outputStream.close();
            resultWb.close();
        } catch (Exception e1) {
            e1.printStackTrace();
        }
    }

    /**
     * 获取类的属性对应单元格标题和列宽
     */
    private static HashMap<Integer, TitleAndCloumn> getTitleAndCloumnMap(Class<?> clz) {
        HashMap<Integer, TitleAndCloumn> orderTitleAndCloumnMap = new HashMap<>();
        Field[] fs = clz.getDeclaredFields();
        for (Field f : fs) {
            f.setAccessible(true);
            if (f.isAnnotationPresent(ExcelResources.class)) {
                Integer order = f.getAnnotation(ExcelResources.class).order();
                String title = f.getAnnotation(ExcelResources.class).title();
                int cloumn = f.getAnnotation(ExcelResources.class).cloumn();
                TitleAndCloumn titleAndCloumn = new TitleAndCloumn(title, cloumn);
                orderTitleAndCloumnMap.put(order, titleAndCloumn);
            }
        }
        return orderTitleAndCloumnMap;
    }

    public static HSSFCellStyle getCellStyle(HSSFWorkbook workbook, int fontSize, boolean isBoleaWeight, short fontColor, short groundColor) {
        HSSFCellStyle style = workbook.createCellStyle();
        style.setFillForegroundColor(groundColor);
        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        style.setAlignment(HorizontalAlignment.CENTER);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        style.setBorderBottom(BorderStyle.THIN);
        style.setBorderLeft(BorderStyle.THIN);
        style.setBorderRight(BorderStyle.THIN);
        style.setBorderTop(BorderStyle.THIN);
        style.setWrapText(true);
        HSSFFont font = workbook.createFont();
        font.setFontHeightInPoints((short) fontSize);
        font.setColor(fontColor);
        font.setFontName("宋体");
        font.setBold(isBoleaWeight);
        style.setFont(font);
        return style;
    }

    /**
     * 获取对象的属性对应单元格坐标和值的键值对
     */
    private static HashMap<Integer, String> getValueMap(Object obj) throws IllegalAccessException {
        HashMap<Integer, String> result = new HashMap<>();
        Class<?> clz = obj.getClass();
        Field[] fs = clz.getDeclaredFields();
        for (Field f : fs) {
            f.setAccessible(true);
            if (f.isAnnotationPresent(ExcelResources.class)) {
                Integer order = f.getAnnotation(ExcelResources.class).order();
                String value = "";
                Object valueObj = f.get(obj);
                if (valueObj != null) {
                    //日期格式进行特殊处理
                    if (f.getType() == Date.class) {
                        String pattern = f.getAnnotation(ExcelResources.class).pattern();
                        if (StringUtils.isEmpty(pattern)) {
                            pattern = "yyyy-MM-dd HH:mm:ss";
                        }
                        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
                        value = sdf.format(valueObj);
                    } else {
                        value = valueObj.toString();
                    }

                }

                result.put(order, value);

            }
        }

        return result;
    }

    /**
     * 根据不同的浏览器生成不同类型中文文件名编码
     */
    public static String encodeFileName(HttpServletRequest request, String fileName)
            throws UnsupportedEncodingException {

        String new_filename = URLEncoder.encode(fileName, "UTF8").replaceAll("\\+", "%20");

        String agent = request.getHeader("USER-AGENT").toLowerCase();
        if (null != agent && -1 != agent.indexOf("msie")) {
            return "filename=\"" + new_filename + "\"";
        } else if (null != agent && -1 != agent.indexOf("applewebkit")) {
            return "filename=\"" + new String(fileName.getBytes("UTF-8"), "ISO8859-1") + "\"";
        } else if (null != agent && -1 != agent.indexOf("opera")) {
            return "filename*=" + new_filename;
        } else if (null != agent && -1 != agent.indexOf("safari")) {
            return "filename=\"" + new String(fileName.getBytes("UTF-8"), "ISO8859-1") + "\"";
        } else if (null != agent && -1 != agent.indexOf("firefox")) {
            return "filename*=" + new_filename;
        } else {
            return "filename=\"" + new_filename + "\"";
        }
    }

}

